#ifndef _animation_h_
#define _animation_h_

#include "graphic_public.h"
#include <string>

class AnimationBase{
public:
	typedef point2d_t vert_t[4];
	AnimationBase(const char * file_name, int row, int col) : m_row(row), m_col(col), m_count(0), m_tex(file_name) {
		
		m_coords.reset(new vert_t[row * col]);
		GLfloat width = m_tex.getTexture()->getMaxS()/ col;
		GLfloat height = m_tex.getTexture()->getMaxT() / row;		
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				m_coords[m_count][0] = j*width,	(i+1)*height;
				m_coords[m_count][1] = j*width, i*height;
				m_coords[m_count][2] = (j+1)*width,	i*height;
				m_coords[m_count][3] = (j+1)*width,	(i+1)*height;			
				m_count++;
			}
		}		
	}
	virtual void getFrameTex() = 0;
	virtual bool runningOut() = 0;
	~AnimationBase() {}
	
protected:
	ExTexture2D m_tex;
	boost::scoped_array<vert_t> m_coords;
	int m_row;
	int m_col;
	int m_count;
	NONCOPYABLE_OBJCT(AnimationBase)
};

class ExplosionAnimation : public AnimationBase{
public:
	ExplosionAnimation(const char * file_name, int row, int col) : AnimationBase(file_name, row, col) , m_frame(0){
		cpVect *dst = m_originalVerts;
		double width = m_tex.getTexture()->getContentSizeInPixels().width / m_col;
		double height = m_tex.getTexture()->getContentSizeInPixels().height / m_row;
		width /= 2.0;
		height /= 2.0;
		dst[0] = cpv(-width, -height);
		dst[1] = cpv(-width, height);
		dst[2] = cpv(width, height);
		dst[3] = cpv(width, -height);		
	}
	~ExplosionAnimation() {}
	vert_t & getVerts() { return m_verts; }
	const cpVect * getOriginalVerts() { return m_originalVerts;}
	virtual void getFrameTex() {
		int index = m_frame/2;
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		m_frame++;
	}
	void draw()
	{
		glEnable(GL_TEXTURE_2D);
//		glEnable(GL_BLEND);
//		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		glBindTexture(GL_TEXTURE_2D, m_tex.getTexture()->getName());
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glVertexPointer(2, GL_FLOAT, 0, &m_verts);
		getFrameTex();
		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
		//glDisable(GL_TEXTURE_2D);
		
	}
	
	virtual void reset() {m_frame = 0;}
	
	virtual bool runningOut() {
		return m_frame >= m_count*2;
	}
protected:
	vert_t m_verts;
	int m_frame;
	cpVect m_originalVerts[4];
};

class TotemObjFallen : public ExplosionAnimation {
public:
	TotemObjFallen(const char * file_name, int row, int col) : ExplosionAnimation(file_name, row, col) {
	}
	
	virtual void getFrameTex() {
		int index = m_frame/1;
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		m_frame++;
	}	
	virtual bool runningOut() {
		return m_frame >= (m_count*1);
	}
};


const int FADE_INTERVAL = 10;
class TotemObjBurnning : public ExplosionAnimation {
public:
	TotemObjBurnning(const char * file_name, int row, int col) : ExplosionAnimation(file_name, row, col), m_fade(0) {
	}
	
	virtual void getFrameTex() {
		int index = m_frame/2;
		if (index >= m_count) {
			index = m_count-1;
			m_fade += 1.0f/FADE_INTERVAL;
			
		}
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		
		m_frame++;
	}
	virtual void reset() {
		m_frame = 0;
		m_fade = 0;
	}

	void draw(){
		glColor4f(1.0, 1.0, 1.0, 1.0 - m_fade);
		ExplosionAnimation::draw();
		glColor4f(1.0, 1.0, 1.0, m_fade);
		m_drawNormal();
		glColor4f(1.0, 1.0, 1.0, 1.0);
	}
	virtual bool runningOut() {
		return m_frame >= (m_count*2 + FADE_INTERVAL);
	}
	boost::function<void()> & getDrawNormalFunction() {return m_drawNormal; };
protected:
	GLfloat m_fade;
	boost::function<void()> m_drawNormal;
};

inline void setVertexRot(point2d_t *dst, const cpVect *src, const cpVect &pos, const cpVect &rot)
{
	for(int i=0; i<4; i++){
		cpVect v = cpvadd( pos, cpvrotate(src[i], rot) );
		dst[i] = (float_t)v.x, (float_t)v.y;
	}
}

class TotemObjBroken : public ExplosionAnimation {
public:
	TotemObjBroken(const char * file_name, int row, int col) : ExplosionAnimation(file_name, row, col) {
		reset();
	}
	
	virtual void getFrameTex() {
		int index = m_frame/2;
		if (index >= m_count) index = m_count-1;
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		m_frame++;
	}	
	virtual bool runningOut() {
		return false;
	}
	//virtual void reset() {m_frame = 9;}
};

class TotemObjPass : public TotemObjBroken {
public:
	TotemObjPass(const char * file_name, int row, int col) : TotemObjBroken(file_name, row, col) {
	}
	virtual void getFrameTex() {
		int index = m_frame/1;
		glTexCoordPointer(2, GL_FLOAT, 0, &m_coords[index%m_count]);
		m_frame++;
	}	
};

template <typename T>
T * getAnimationFile(const totem_obj_info_t *info)
{
	using namespace std;
	const char *name;
	
	if (boost::is_same<ExplosionAnimation, T>::value) {
 
		if (string::npos != info->texture_name.find(STR_PLASTICS)) {
			name = "plastics_explode.png2";
		}
		else if (string::npos != info->texture_name.find(STR_LIGHT_BOX)) {
			name = "light_explode.png2";
		}
		else if (string::npos != info->texture_name.find(STR_TNT_BOX)) {
			name = "tnt_explode.png2";
			return new T(name, 2, 5);
		}
		else {
			name = "wood_explode.png2";
		}
		return new T(name, 1, 6);		
	}	
	else if (boost::is_same<TotemObjFallen, T>::value) {
		if (string::npos != info->texture_name.find('2')) name = "fallen2.png";
		else name = "fallen.png";
		return new T(name, 1, 8);		
	}
	else if (boost::is_same<TotemObjBurnning, T>::value) {
		if (string::npos != info->texture_name.find('2')) name = "burnning2.png";
		else name = "burnning.png";
		return new T(name, 1, 3);
	}
	else if (boost::is_same<TotemObjBroken, T>::value) {
		if (string::npos != info->texture_name.find('2')) name = "broken2.png";
		else name = "broken.png";
		return new T(name, 1, 10);
	}
	else if (boost::is_same<TotemObjPass, T>::value) {
		if (string::npos != info->texture_name.find('2')) name = "game_pass2.png";
		else name = "game_pass.png";
		return new T(name, 1, 8);
	}
	else {
		ASSERT(0);
	}
}

typedef struct tagSceneAnimationDelegate{
	boost::function<void()> _update;
	boost::function<void()> _free;
	tagSceneAnimationDelegate() {
		if (NULL != _free) _free();
	}
} SceneAnimation_delegate_t;

void setSceneAnimation(SceneAnimation_delegate_t &sceneAnimation, const std::string &sceneName);

#endif